﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

class SpawnPointList 
{

    public List<Vector3> spawnPoints = new List<Vector3>();
    int currentSpawnPoint = 0;
    public Room spawnRoom = null;

    public SpawnPointList(List<Room> rooms, int numSpawnPoints, bool coopMode)
    {
        UnityEngine.MonoBehaviour.print("Generating spawn points for " + rooms.Count + ", " + numSpawnPoints + " to create");
        if (numSpawnPoints > rooms.Count) throw new ArgumentException("There must be at least as many rooms as spawn points to create.");

        List<int> roomIndexes = new List<int>();
        for (int i = 0; i < rooms.Count; i++) roomIndexes.Add(i);

        if (!coopMode)
        {
            for (int spawnPointIndex = 0; spawnPointIndex < numSpawnPoints; spawnPointIndex++)
            {
                int randomRoomIndex = roomIndexes[UnityEngine.Random.Range(0, roomIndexes.Count - 1)];
                spawnRoom = rooms[randomRoomIndex];
                Vector3 spawnPoint = new Vector3(spawnRoom.X + spawnRoom.Width / 2, spawnRoom.Y + spawnRoom.Height / 2, 0);
                spawnPoints.Add(spawnPoint);
                roomIndexes.Remove(randomRoomIndex);
            }
        }
        else
        {
            spawnRoom = null;
            int randomRoomIndex = -1;
            while (spawnRoom == null || (spawnRoom.Height * spawnRoom.Width < numSpawnPoints))
            {
                if (randomRoomIndex >= 0) roomIndexes.Remove(randomRoomIndex);
                randomRoomIndex = roomIndexes[UnityEngine.Random.Range(0, roomIndexes.Count - 1)];
                spawnRoom = rooms[randomRoomIndex];
            }

            // The room will hold the players - how do we provide algorithmic certainty of placing them in the room?
            // A spiral pattern makes the most sense. A walking spawn point dropper that moves in a spiral pattern,
            // confined by the logical perimeter of the room.
            Vector3 currentSpawnPoint = new Vector3(spawnRoom.X + spawnRoom.Width / 2, spawnRoom.Y + spawnRoom.Height / 2, 0);
            spawnPoints.Add(currentSpawnPoint);

            Vector3 currentDirection = Vector3.up;

            for (int i = 1; i < numSpawnPoints; i++)
            {
                bool nextSpotFound = false;
                int maxTries = spawnRoom.Width * spawnRoom.Height;
                int currentTry = 0;
                Vector3 nextSpawnPoint = currentSpawnPoint;
                Vector3 lastDirection = currentDirection;
                Vector3 nextDirection = currentDirection;
                while (!nextSpotFound && currentTry < maxTries)
                {
                    // 1. If I'm about to run into a wall, turn
                    switch ((int)(currentDirection.x * 10 + currentDirection.y))
                    {
                        case 1:
                            // up
                            nextDirection = Vector3.right;
                            if (nextSpawnPoint.y == spawnRoom.Y)
                            {
                                // At edge, turn
                                currentDirection = nextDirection;
                            }
                            break;
                        case -1:
                            // down
                            nextDirection = Vector3.left;
                            if (nextSpawnPoint.y == spawnRoom.Y + spawnRoom.Height - 1)
                            {
                                // At edge, turn
                                currentDirection = nextDirection;
                            }
                            break;
                        case 10:
                            // right
                            nextDirection = Vector3.down;
                            if (nextSpawnPoint.x == spawnRoom.X + spawnRoom.Width - 1)
                            {
                                // At edge, turn
                                currentDirection = nextDirection;
                            }
                            break;
                        case -10:
                            // left
                            nextDirection = Vector3.up;
                            if (nextSpawnPoint.x == spawnRoom.X)
                            {
                                // At edge, turn
                                currentDirection = nextDirection;
                            }
                            break;
                    }

                    if (currentDirection == lastDirection)
                    {
                        // We didn't turn; we can proceed forward
                        nextSpawnPoint += currentDirection;

                        if (!spawnPoints.Contains(nextSpawnPoint))
                        {
                            spawnPoints.Add(nextSpawnPoint);
                            nextSpotFound = true;
                            currentDirection = nextDirection;
                            currentSpawnPoint = nextSpawnPoint;
                        }

                    }

                }

            }


        }
    }

    public Vector3 GetNextSpawnPoint()
    {
        if (spawnPoints.Count == 0) return Vector3.zero;
        Vector3 spawnPoint = spawnPoints[currentSpawnPoint++];
        if (currentSpawnPoint >= spawnPoints.Count)
            currentSpawnPoint = 0;
        return spawnPoint;
    }

    private SpawnPointList() { }

    internal static SpawnPointList GetEmptyList()
    {
        return new SpawnPointList();
    }
}
